////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                            //
//                                                         WNProject                                                          //
//                                                                                                                            //
//            This file is distributed under the BSD 2-Clause open source license. See License.txt for details.               //
//                                                                                                                            //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// Library Version -------------------------------------------------------------------------------------------------------------
//      Major Version: WN_LIBRARIES_VERSION / 100000
//      Minor Version: WN_LIBRARIES_VERSION / 100 % 1000
//      Patch Level:   WN_LIBRARIES_VERSION % 100

// Calling Conventions ---------------------------------------------------------------------------------------------------------
//      WN_CDECL_BEGIN / WN_CDECL_END
//      WN_STDCALL_BEGIN / WN_STDCALL_END
//      WN_FASTCALL_BEGIN / WN_FASTCALL_END

// Keyword ---------------------------------------------------------------------------------------------------------------------
//      WN_INLINE
//      WN_RESTRICT

// Properties ------------------------------------------------------------------------------------------------------------------
//      WN_NO_INLINE
//      WN_THREAD_LOCAL
//      WN_ALIGNMENT

// Compiler (Only 1 of the following) ------------------------------------------------------------------------------------------
//      _WN_MSVC    - Microsoft Visual C++ compiler
//      _WN_GNUC    - GNU C compiler (i.e. gcc/g++)

// Platform (Only 1 of the following) ------------------------------------------------------------------------------------------
//      _WN_WINDOWS - Microsoft Windows
//      _WN_LINUX   - Linux

// Architecture (Only 1 of the following) --------------------------------------------------------------------------------------
//      _WN_X86     - Defined for all x86 based architectures (i.e. x86, x86-64, etc.)
//      _WN_ARM     - Defined for all ARM based architectures. The value will be the ARM version (i.e. 4, 5, 6, 7)
//      _WN_MIPS    - Defined for all MIPS based architectures
//      _WN_PPC     - Defined for all PowerPC based architectures (i.e. ppc, ppc64, etc.)

// Processor Bit Width (Only 1 of the following) -------------------------------------------------------------------------------
//      _WN_32_BIT  - Defined if architecture is 32-bit
//      _WN_64_BIT  - Defined if architecture is 64-bit

// Endianess (Only 1 of the following) -----------------------------------------------------------------------------------------
//      _WN_ENDIAN_LITTLE
//      _WN_ENDIAN_BIG
//      _WN_ENDIAN_UNKNOWN - Requires runtime check due to Bi-endian architecture

// Character Set ---------------------------------------------------------------------------------------------------------------
//      _WN_UNICODE
//      _WN_ANSI

// Configuration ---------------------------------------------------------------------------------------------------------------
//      _WN_DEBUG

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#pragma once

#ifndef __WN_CORE_PLATFORM_H__
#define __WN_CORE_PLATFORM_H__

#ifndef __cplusplus
    #error "WNLibraries is a set of C++ only libraries.  Please use with a C++ compiler and/or compile for C++."
#else
    #define __WN_CPLUSPLUS __cplusplus
#endif

#ifdef _HAS_EXCEPTIONS
    #undef _HAS_EXCEPTIONS
#endif

#define _HAS_EXCEPTIONS 0

#if (defined DEBUG || defined _DEBUG) && !defined NDEBUG
    #define _WN_DEBUG
#else
    #define _WN_RELEASE
#endif

#if defined UNICODE || defined _UNICODE
    #define _WN_UNICODE
#else
    #define _WN_ANSI
#endif

#ifdef _MSC_VER // Microsoft Visual C++
    #if _MSC_VER < 1500 || _MSC_FULL_VER < 150030729
        #error "Compiler not supported: MSVC 9 SP1 (Visual Studio 2008 SP1) or higher must be used"
    #endif

    #define _WN_MSVC _MSC_FULL_VER

    #define WN_INLINE __forceinline
    #define WN_RESTRICT __restrict
    #define WN_THREAD_LOCAL __declspec(thread)

    #if _MSC_VER >= 1600 || (defined _MSC_EXTENSIONS && defined _NATIVE_NULLPTR_SUPPORTED)
        #define __WN_HAS_NULLPTR
        #define __WN_HAS_NULLPTR_CUSTOM
    #endif

    #if _MSC_VER >= 1600
        #define __WN_HAS_STATIC_ASSERT
        #define __WN_HAS_RVALUE_REFERENCES
    #endif

    #if _MSC_VER >= 1700
        #define __WN_HAS_VARIADIC_TEMPLATES
    #endif

    #if defined _M_X64 || defined _M_AMD64
        #define _WN_X86
        #define _WN_64_BIT

        // For some reason the following don't get properly defined at editing time just at compile time.  Define them so
        // intellisense doesn't complain
        #ifndef _M_AMD64
            #define _M_AMD64

            #ifndef _AMD64_
                #define _AMD64_
            #endif
        #endif
    #elif defined _M_IX86
        #define _WN_X86
        #define _WN_32_BIT
    #elif defined _M_ARM
        #define _WN_ARM _M_ARM
        #define _WN_32_BIT
    #endif

    #if defined _WIN32 || defined _WIN64
        #define _WN_WINDOWS

        #include <winsock2.h>
        #include <windows.h>

        #define WN_OSCALL_BEGIN WINAPI
        #define WN_OSCALL_END
    #endif

    #ifdef _WN_X86
        #define WN_CDECL_BEGIN __cdecl
        #define WN_CDECL_END

        #define WN_STDCALL_BEGIN __stdcall
        #define WN_STDCALL_END

        #define WN_FASTCALL_BEGIN __fastcall
        #define WN_FASTCALL_END

        #define __WN_FPU_SUPPORTED

        #ifndef _WN_64_BIT
            #define __WN_MMX_SUPPORTED
            #define __WN_3DNOW_SUPPORTED
        #endif

        #define __WN_SSE_SUPPORTED
        #define __WN_SSE2_SUPPORTED
        #define __WN_SSE3_SUPPORTED
        #define __WN_SSSE3_SUPPORTED
        #define __WN_SSE4_1_SUPPORTED
        #define __WN_SSE4_2_SUPPORTED
        #define __WN_SSE4A_SUPPORTED
        #define __WN_AES_SUPPORTED

        #if _MSC_VER > 1600 || _MSC_FULL_VER >= 160040219
            #define __WN_AVX_SUPPORTED
            #define __WN_FMA4_SUPPORTED
            #define __WN_XOP_SUPPORTED
        #endif

        #if _MSC_VER > 1600
            #define __WN_FMA3_SUPPORTED
            #define __WN_CVT16_SUPPORTED
        #endif
    #endif
#elif (defined __GNUC__ || defined __GNUG__) || __clang__ // GNU C or Clang
    #ifdef __clang__
        #if __clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 1)
            #error "Compiler not supported: Clang 3.1 or higher must be used"
        #endif

        #ifdef __clang_patchlevel__
            #define _WN_CLANG (__clang_major__ * 100000 + __clang_minor__ * 100 + __clang_patchlevel__)
        #else
            #define _WN_CLANG (__clang_major__ * 100000 + __clang_minor__ * 100)
        #endif

        #ifndef __has_feature
            #define __has_feature(x) 0
        #endif

        #ifndef __has_extension
            #define __has_extension __has_feature
        #endif

        #if __has_feature(cxx_nullptr) || __has_extension(cxx_nullptr)
            #define __WN_HAS_NULLPTR
        #endif

        #if __has_feature(cxx_rvalue_references) || __has_extension(cxx_rvalue_references)
            #define __WN_HAS_RVALUE_REFERENCES
        #endif

        #if __has_feature(cxx_static_assert) || __has_extension(cxx_static_assert)
            #define __WN_HAS_STATIC_ASSERT
        #endif

        #if __has_feature(cxx_variadic_templates) || __has_extension(cxx_variadic_templates)
            #define __WN_HAS_VARIADIC_TEMPLATES
        #endif

        // Work around a header bug with CLANG/ see http://lists.cs.uiuc.edu/pipermail/cfe-dev/2011-February/013207.html
        namespace std { class type_info; }
    #elif defined __GNUC__
        #if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 4)
            #error "Compiler not supported: GNU C 4.4.0 or higher must be used"
        #endif

        #ifdef __GNUC_PATCHLEVEL__
            #define _WN_GNUC (__GNUC__ * 100000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
        #else
            #define _WN_GNUC (__GNUC__ * 100000 + __GNUC_MINOR__ * 100)
        #endif

        #define WN_INLINE __inline__

        #ifdef __GXX_EXPERIMENTAL_CXX0X__
            #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6)
                #define __WN_HAS_NULLPTR
            #endif

            #define __WN_HAS_STATIC_ASSERT
        #else
            #ifdef __GNUG__
                #define __WN_HAS_NULLPTR_CUSTOM
            #endif
        #endif

        #define __WN_HAS_RVALUE_REFERENCES
        #define __WN_HAS_VARIADIC_TEMPLATES
    #endif

    #define WN_RESTRICT __restrict__
    #define WN_THREAD_LOCAL __thread

    #if defined __x86_64 || defined __x86_64__ || defined __amd64 || defined __amd64__
        #define _WN_X86
        #define _WN_64_BIT
    #elif defined i386 || defined __i386 || defined __i386__
        #define _WN_X86
        #define _WN_32_BIT
    #elif defined arm || defined __arm__
        #if defined __ARM_ARCH_7__ || defined __ARM_ARCH_7A__ || defined __ARM_ARCH_7R__ || \
            defined __ARM_ARCH_7M__ || defined __ARM_ARCH_7EM__ || defined _ARM_ARCH_7
            #define _WN_ARM 7
        #elif defined __ARM_ARCH_6__ || defined __ARM_ARCH_6J__ || defined __ARM_ARCH_6K__ || \
              defined __ARM_ARCH_6Z__ || defined __ARM_ARCH_6ZK__ || defined __ARM_ARCH_6T2__ || \
              defined __ARM_ARCH_6M__ || defined _ARM_ARCH_6
            #define _WN_ARM 6
        #elif defined __ARM_ARCH_5__ || defined __ARM_ARCH_5T__ || defined __ARM_ARCH_5E__ || \
              defined __ARM_ARCH_5TE__ || defined __ARM_ARCH_5TEJ__ || defined _ARM_ARCH_5
            #define _WN_ARM 5
        #elif defined __ARM_ARCH_4__ || defined __ARM_ARCH_4T__ || defined _ARM_ARCH_4
            #define _WN_ARM 4
        #endif

        #define _WN_32_BIT
    #elif defined mips || defined __mips__
        #define _WN_MIPS
        #define _WN_32_BIT
    #elif defined __powerpc64 || defined __powerpc64__ || defined __POWERPC64__ || defined __ppc64__
        #define _WN_PPC
        #define _WN_64_BIT
    #elif defined __powerpc || defined __powerpc__ || defined __POWERPC__ || defined __ppc__
        #define _WN_PPC
        #define _WN_32_BIT
    #endif

    #if defined linux || defined __linux || defined __linux__
        #define _WN_LINUX
        #include <stdlib.h>

        #ifndef _WN_64_BIT
            #define WN_OSCALL_BEGIN
            #define WN_OSCALL_END __attribute__((cdecl))
        #endif
    #endif

    #ifdef __BIG_ENDIAN__
        #define _WN_ENDIAN_BIG
    #elif defined __LITTLE_ENDIAN__
        #define _WN_ENDIAN_LITTLE
    #else
        #define _WN_ENDIAN_UNKNOWN
    #endif

    #ifdef _WN_X86
        #define __WN_FPU_SUPPORTED

        #ifndef _WN_64_BIT
            #define WN_CDECL_BEGIN
            #define WN_CDECL_END __attribute__((cdecl))

            #define WN_STDCALL_BEGIN
            #define WN_STDCALL_END __attribute__((stdcall))

            #define WN_FASTCALL_BEGIN
            #define WN_FASTCALL_END __attribute__((fastcall))

            #define __WN_MMX_SUPPORTED
            #define __WN_3DNOW_SUPPORTED
        #endif

        #define __WN_SSE_SUPPORTED
        #define __WN_SSE2_SUPPORTED
        #define __WN_SSE3_SUPPORTED
        #define __WN_SSSE3_SUPPORTED
        #define __WN_SSE4_1_SUPPORTED
        #define __WN_SSE4_2_SUPPORTED
        #define __WN_SSE4A_SUPPORTED

        #ifdef __GNUC__
            #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 4)
                #define __WN_AES_SUPPORTED
                #define __WN_AVX_SUPPORTED
            #endif

            #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5)
                #define __WN_FMA4_SUPPORTED
                #define __WN_XOP_SUPPORTED
            #endif

            #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 7)
                #define __WN_FMA3_SUPPORTED
                #define __WN_CVT16_SUPPORTED
            #endif
        #endif
    #endif
#else
    #error "Compiler not supported"
#endif

#ifndef WN_INLINE
    #define WN_INLINE inline
#endif

#ifdef _WN_X86
    #define __WN_FPU_AVAILABLE

    #ifdef _WN_64_BIT
        #define __WN_SSE_AVAILABLE
        #define __WN_SSE2_AVAILABLE
    #endif

    #ifndef _WN_ENDIAN_LITTLE
        #define _WN_ENDIAN_LITTLE
    #endif
#elif defined _WN_PPC
    #ifndef _WN_ENDIAN_BIG
        #define _WN_ENDIAN_BIG
    #endif
#endif

#if !defined _WN_ENDIAN_LITTLE && !defined _WN_ENDIAN_BIG
    #ifndef _WN_ENDIAN_UNKNOWN
        #define _WN_ENDIAN_UNKNOWN
    #endif
#else
    #ifdef _WN_ENDIAN_UNKNOWN
        #undef _WN_ENDIAN_UNKNOWN
    #endif
#endif

#ifndef WN_CDECL_BEGIN
    #define WN_CDECL_BEGIN
#endif

#ifndef WN_CDECL_END
    #define WN_CDECL_END
#endif

#ifndef WN_STDCALL_BEGIN
    #define WN_STDCALL_BEGIN
#endif

#ifndef WN_STDCALL_END
    #define WN_STDCALL_END
#endif

#ifndef WN_FASTCALL_BEGIN
    #define WN_FASTCALL_BEGIN
#endif

#ifndef WN_FASTCALL_END
    #define WN_FASTCALL_END
#endif

#define WN_LIBRARIES_VERSION 20000 // 0.2.0

#endif // __WN_CORE_PLATFORM_H__
